// Copyright 2022 Adam Barth
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

library astar;

import 'dart:math' as math;

import 'package:flame/components.dart';

import 'astar.dart';

/// Whether the given location is passable in the grid.
typedef IsPassableCallback = bool Function(double x, double y);

/// A* pathfinding algorithm in a 2D grid.
///
/// See [PathFinder] for pathfinding in an arbitrary graph.
class PathFinder2D extends PathFinder<Vector2> {
  /// Whether the given location is passable in the grid.
  ///
  /// This is used to determine which locations are valid to move to. This
  /// function is responsible for bounds checking.
  final IsPassableCallback isPassable;

  /// Whether to allow diagonal movement.
  final bool allowDiagonal;

  /// Creates a new pathfinder.
  PathFinder2D({required this.isPassable, this.allowDiagonal = true});

  @override
  double getApproximateDistance(Vector2 a, Vector2 b) => a.distanceTo(b);

  @override
  Iterable<Neighbor<Vector2>> getNeighborsOf(Vector2 node) sync* {
    for (int dx = -1; dx <= 1; ++dx) {
      for (int dy = -1; dy <= 1; ++dy) {
        if (dx == 0 && dy == 0) {
          continue;
        }
        if (!allowDiagonal && dx != 0 && dy != 0) {
          continue;
        }
        final x = node.x + dx;
        final y = node.y + dy;
        if (isPassable(x, y)) {
          yield Neighbor(Vector2(x, y), 16.0);
        }
      }
    }
  }
}